import json
from datetime import datetime, timedelta
from typing import List, Dict, Tuple


class Person:
    """表示一个人的类，记录其到达和通过各个点的时间"""
    def __init__(self, person_id: int, exit_name: str, arrival_time: datetime):
        self.id = person_id
        self.exit_name = exit_name  # 从哪个地铁口出来
        self.arrival_time = arrival_time  # 到达地铁口的时间
        self.security_arrival_time = None  # 到达安检口的时间
        self.security_queue_time = None  # 开始排队安检的时间
        self.security_pass_time = None  # 通过安检的时间
        self.e1_arrival_time = None  # 到达E1口的时间
        self.security_failed = False  # 安检是否不通过
        self.security_retry_time = None  # 重新安检的时间


class PeopleFlowGenerator:
    """人流生成器，根据时间段和地铁口比例生成人流"""
    
    def __init__(self, config_path: str):
        with open(config_path, 'r', encoding='utf-8') as f:
            self.config = json.load(f)
        
        self.subway_exits = self.config["subway_exits"]
        self.person_counter = 0
    
    def parse_time(self, time_str: str) -> datetime:
        """将时间字符串转换为datetime对象"""
        return datetime.strptime(time_str, "%H:%M")
    
    def time_diff_minutes(self, start: datetime, end: datetime) -> int:
        """计算两个时间点之间的分钟数"""
        return int((end - start).total_seconds() / 60)
    
    def distribute_people_to_exits(self, total_people: int) -> Dict[str, int]:
        """根据比例将总人数分配到各个地铁口"""
        distribution = {}
        
        # 获取比例
        b_ratio = self.subway_exits["B"]["ratio"]
        c_ratio = self.subway_exits["C"]["ratio"]
        d_ratio = self.subway_exits["D"]["ratio"]
        
        # 计算每个地铁口的人数，使用四舍五入确保更精确
        b_people = round(total_people * b_ratio)
        c_people = round(total_people * c_ratio)
        d_people = round(total_people * d_ratio)
        
        # 调整总和，确保等于总人数
        total_allocated = b_people + c_people + d_people
        diff = total_people - total_allocated
        
        # 如果有差异，优先分配给比例最大的地铁口
        if diff != 0:
            if b_ratio >= c_ratio and b_ratio >= d_ratio:
                b_people += diff
            elif c_ratio >= b_ratio and c_ratio >= d_ratio:
                c_people += diff
            else:
                d_people += diff
        
        distribution["B"] = b_people
        distribution["C"] = c_people
        distribution["D"] = d_people
        
        return distribution
    
    def generate_people_for_period(self, period: Dict[str, str], base_date: datetime = None) -> List[Person]:
        """为特定时间段生成人流"""
        if base_date is None:
            base_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        
        start_time = self.parse_time(period["start_time"])
        end_time = self.parse_time(period["end_time"])
        total_people = period["people_count"]
        
        # 计算时间段长度（分钟）
        period_minutes = self.time_diff_minutes(start_time, end_time)
        
        # 将人数分配到各个地铁口
        exit_distribution = self.distribute_people_to_exits(total_people)
        
        people = []
        
        # 为每个地铁口生成人流
        for exit_name, exit_people in exit_distribution.items():
            if exit_people == 0:
                continue
                
            # 计算每个人到达的时间间隔（秒）
            interval_seconds = period_minutes * 60 / exit_people
            
            # 生成该地铁口的人流
            for i in range(exit_people):
                # 计算每个人的到达时间
                arrival_seconds = int(i * interval_seconds)
                arrival_time = base_date + timedelta(
                    hours=start_time.hour, 
                    minutes=start_time.minute,
                    seconds=arrival_seconds
                )
                
                # 创建人员对象
                person = Person(self.person_counter, exit_name, arrival_time)
                people.append(person)
                self.person_counter += 1
        
        # 按到达时间排序
        people.sort(key=lambda p: p.arrival_time)
        
        return people
    
    def generate_morning_flow(self, base_date: datetime = None) -> List[Person]:
        """生成上午的人流"""
        all_people = []
        
        for period in self.config["morning_periods"]:
            period_people = self.generate_people_for_period(period, base_date)
            all_people.extend(period_people)
        
        return all_people
    
    def generate_afternoon_flow(self, base_date: datetime = None) -> List[Person]:
        """生成下午的人流"""
        all_people = []
        
        for period in self.config["afternoon_periods"]:
            period_people = self.generate_people_for_period(period, base_date)
            all_people.extend(period_people)
        
        return all_people